
--------------------------------------------------
--- Copyright：  迷你玩-海马
--- Description：从管理中心服务器同步lua配置文件
--- 功能: 向center查询指定名字的配置文件是否有更新
--------------------------------------------------

local require  = require;
local ngx      = ngx;
local debug    = debug;
local string   = string;
local tonumber = tonumber;
local setmetatable = setmetatable;
local pairs = pairs
local type  = type


----数据变量----
local uu         = require("modules.commhm.utils");
local log        = require("modules.commhm.log");

local CLuaConfig = require("modules.center_server.CLuaConfig");
local ns_network = require("modules.commhm.network");

local ns_auth_comm_checker = require("modules.commhm.auth_comm_checker")
local CNgxTimerWrap        = require("modules.commhm.ngxTimerWrap" )

local ns_env                 = require( "modules.env.env" );
local ns_const_server_config = require("modules.commhm.const_server_config");


local table = table
local table_concat =table.concat


local FOO = {
    _VERSION = '0.12.1',
    config_cache_root = '/tmp/centerConfigCache/',   ---作为客户端的本地cache地址

    ---配置文件池子
    config_pool = {
        --file_name1 = {
            --server_name1 = CLuaConfig;
            --server_name2 = CLuaConfig;
        --},
    },
};


--[[

---每120秒检查一下该配置文件是否有变化，如果有就调用自定义回调函数
---会在服务器本地建立cache，自动识别环境，自动对比md5来提高效率
---首次加载会加载本地cache，再核对远程文件来对比是否有改动
---用法例子：
ns_luaConfigMgr.register_config_file_change( "server_config", 120, FOO.callback_fresh_my_config, "map" )

---回调函数例子
function FOO.callback_fresh_my_config( config_file_content_ )
    local config_ =  table.loadstring( config_file_content_ )
    uu.var_dump( config_ )
end


---需要require头文件:
local ns_luaConfigMgr = require("modules.center_server.luaConfigProxy")

--]]



---监控指定的lua配置文件的变化，如果有变化，就回调
---file_name_   = 文件名字  ma_config server_config version
---expire_time_ = 检查周期  120秒
---cb_          = 回调函数
---server_name_ = 服务模块名字   map profile cm rent
---opt_         = 自定义的参数，作为第二个参数调用回调cb_函数
function FOO.register_config_file_change( file_name_, expire_time_, cb_, server_name_ , opt_)

    if  not ngx.shared.miniw3 then
        local info_str_ =
[[未在配置文件中配置 ngx.shared.miniw3, 配置文件共享内存功能无法使用，性能会比较低，
在nginx conf http模块中增加  lua_shared_dict miniw3 20m;  即可。
]];
        log.error( "not set nginx config miniw3: " .. info_str_ )
        log.day_list( "center_server_client",       "not_set_miniw3", info_str_, debug.traceback() )
        log.day_list( "error_center_server_client", "not_set_miniw3", info_str_, debug.traceback() )
    end

    if  not (file_name_ and server_name_) then
        log.error( "register_config_file_change params error" )
        return
    end

    ---标准化 [ 60 到 3600 ]
    if  not expire_time_ then
        expire_time_ = 120
        log.day_list_simple( "center_server_client", ngx.worker.id(), "error_set_expire_time", expire_time_ )
    elseif  expire_time_ < 60 then
        log.day_list_simple( "center_server_client", ngx.worker.id(), "error_set_expire_time", expire_time_ )
        expire_time_ = 60
    elseif  expire_time_ > 3600 then
        expire_time_ = 3600
    end

    ----增加到回调列表
    if  not FOO.config_pool[ file_name_ ] then
        FOO.config_pool[ file_name_ ] = {}
    end

    if  FOO.config_pool[ file_name_ ][ server_name_ ] then
        log.day_list_simple( "center_server_client", ngx.worker.id(), "register_config_error_repeat",
                file_name_, server_name_, expire_time_, debug.traceback() )
        log.error( "register_config_error_repeat_" .. server_name_ )
        return
    else
        log.day_list_simple( "center_server_client",ngx.worker.id(), "register_config_add_func_list",
                file_name_, server_name_, expire_time_, uu.to_str( FOO.config_pool[ file_name_ ] ) )
    end

    local function func_()
        --- has_change_ : 0=无变化 1=有变化 2=首次加载cache
        local has_change_, content_ = FOO.getRemoteLuaConfig( file_name_, server_name_, expire_time_ )
        if  has_change_ > 0 then
            if  cb_ then
                cb_( content_ , opt_)
                if  has_change_ == 2 then
                    log.day_list_simple( "center_server_client", ngx.worker.id(), "lua_config_first_load_old",
                            file_name_, server_name_, expire_time_ )
                else
                    log.day_list_simple( "center_server_client", ngx.worker.id(), "lua_config_changed",
                            file_name_, server_name_, expire_time_ )
                end
            end
        else
            --if  ngx.worker.id() == 0 then
                log.day_list_simple( "center_server_client", ngx.worker.id(), "lua_config_unchanged",
                        file_name_, server_name_, expire_time_ )
            --end
        end
    end

    local timer_ = CNgxTimerWrap:new()
    timer_:ngx_timer_at( 0, func_ )     ---立即拉取一次
    timer_:ngx_timer_every( expire_time_, func_ )
    log.day_list_simple( "center_server_client", ngx.worker.id(), "register_config_file_change",
            file_name_, server_name_, expire_time_ )

end



--- 从管理中心服务器拉取远程服务器的配置文件
--- 先通过上次记录的配置文件的md5值去远程比对，如果未改动，就使用本地cache
--- 返回值：
--- has_change_ : 0=无变化 1=有变化 2=首次加载cache
--- content_    : 有变化则返回值
function FOO.getRemoteLuaConfig( file_name_, server_name_, expire_time_ )

    local lua_config_

    if  not FOO.config_pool[ file_name_ ] then
        FOO.config_pool[ file_name_ ] = {}
    end

    if  FOO.config_pool[ file_name_ ][ server_name_ ] then
        lua_config_ = FOO.config_pool[ file_name_ ][ server_name_ ]
    else
        ---首次加载，先使用旧文件内容
        lua_config_ = CLuaConfig:new( FOO.config_cache_root, file_name_, ns_env.debug )
        FOO.config_pool[ file_name_ ][ server_name_ ] = lua_config_

        lua_config_:loadFromOldFile()

        if  lua_config_.content and  #lua_config_.content > 0 then
            return 2, lua_config_.content
        end
    end

    --log.day_list_simple( "center_server_client", "----lua_config_", uu.to_str(lua_config_) )

    --先查缓存
    local file_info_    --配置文件内容
    local http_get_     --是否发起过远程调用
    local key_ = lua_config_.file_name .. '_' .. (lua_config_.fn_md5 or 'nil') .. '_' .. ns_env.debug

    if  ngx.shared.miniw3 and lua_config_.fn_md5 then
        file_info_ = uu.get_server_cache_table( 3, key_ )
    end
    if  file_info_ then
        if  file_info_.worker_id == ngx.worker.id() then
            -- worker_id一致的情况下，也发起调用
            file_info_ = FOO.WWW_getRemoteLuaConfig( lua_config_.file_name, lua_config_.fn_md5, server_name_ )
            http_get_ = 1
        else
            --可以使用cache
            log.day_list_simple( "center_server_client", ngx.worker.id(), "use_config_cache", key_ )
        end
    else
        file_info_ = FOO.WWW_getRemoteLuaConfig( lua_config_.file_name, lua_config_.fn_md5, server_name_ )
        http_get_ = 1
    end

    if  type(file_info_) == 'table' then
        uu.var_dump( file_info_ )
        if  file_info_.ret == 0 then
            ---文件未变化
            if  http_get_ and ngx.shared.miniw3 then
                file_info_.worker_id = ngx.worker.id()
                uu.set_server_cache_table( 3, key_, file_info_, expire_time_ + 10 )  --每N秒发起一次网络调用
                log.day_list_simple( "center_server_client", ngx.worker.id(), "set_config_cache", key_ )
            end
        elseif  file_info_.ret == 1 and file_info_.content_base64 then
            local ret_ = lua_config_:setContentBase64( file_info_.content_base64, file_info_.md5 )
            if  ret_ == 0 and lua_config_.content and #lua_config_.content > 0 then
                return 1, lua_config_.content
            else
                log.day_list_simple( "center_server_client", ngx.worker.id(), "content_is_nil", uu.to_str(lua_config_) )
            end
        end
    else
        log.day_list_simple( "center_server_client", ngx.worker.id(), "error_content_is_not_table", file_name_ )
        log.error( "error_content_is_not_table_" .. file_name_ )

        --严重错误，上报
        local key_   = 'getRemoteLuaConfig_' .. file_name_
        local value_ = 'from=' .. server_name_
        FOO.WWW_fatalReport( 1, key_, 30, value_, 1 )
    end

    return 0   ---无变化
end



---远程拉取新配置文件
function FOO.WWW_getRemoteLuaConfig( file_name_, fn_md5_, server_name_ )

    local t_ = {
        cmd = 'getLuaConfigFileInfo',
        uin = 12345,
        time = uu.now(),

        fn = file_name_,
        server_name = server_name_,

        env = ns_env.debug,
        worker_id = ngx.worker.id(),
        fn_md5 = fn_md5_,
    }

    t_.token = ns_auth_comm_checker.gen_comm_inner_token( t_.uin, t_.time, t_.cmd );
    local url_ext_ = ngx.encode_args( t_ )

    for i=1, #ns_const_server_config.center_url_list do
        local url_ = ns_const_server_config.center_url_list[i] .. '?' .. url_ext_
        local ret, body = ns_network.getHttpPage( url_ );
        --log.debug(ret .. "|" .. (body or 'nil'));
        if  ret == 200 then
            local ret_fin_ = table.loadstring(body);
            if  type(ret_fin_) == 'table' then
                return ret_fin_
            end
        else
            log.error("call getHttpPage error., url = ", url_);
        end
    end

end




----------------------------------------------------------------------
---延迟执行一个任务
FOO.timer_at = function( delay_, func_, params_ )
    local timer_ = CNgxTimerWrap:new()
    return timer_:ngx_timer_at( delay_, func_,  params_ )
end


---定期执行一个任务
FOO.timer_every = function( delay_, func_, params_ )
    local timer_ = CNgxTimerWrap:new()
    return timer_:ngx_timer_every( delay_, func_, params_  )
end


return FOO;
